home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / so91.lha / Scan / Scan.txt < prev   
Encoding:
Text File  |  1991-10-23  |  13.8 KB  |  297 lines

  1. (c)  Copyright 1991 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice,
  3. and is provided "as is" without warranty of any kind, either expressed
  4. or implied.  The entire risk as to the use of this information is
  5. assumed by the user.
  6.  
  7.  
  8. Directory Scanning
  9.  
  10.  
  11. by Ewout Walraven
  12.  
  13.  
  14.  
  15.  
  16. Prior to release 2.0, examining the contents of directories using
  17. dos.library required the use of two functions: Examine() and ExNext().
  18. Although these routines perform the task for which they were intended, they
  19. have limitations.  One is that these functions require stepping through a
  20. directory one entry at a time.  For most applications that need to do
  21. directory scanning, it would more efficient to scan a directory in one pass
  22. rather than many.  This would significantly reduce the time spent scanning.
  23. Also, these functions don't know anything about the AmigaDOS wildcards, so
  24. any wildcard processing must be done by the application, not by the OS.
  25.  
  26.  
  27. Atomic Directory Scanning
  28.  
  29. The dos.library function ExAll() is a powerful, V37 replacement for the
  30. Examine() and ExNext() functions:
  31.  
  32. BOOL ExAll(BPTR mydirlock, UBYTE *mybuffer,
  33.            LONG mybuffersize, LONG mydatatype,
  34.            struct ExAllControl *myexall);
  35.  
  36. ExAll() performs a one pass directory scan on a directory lock (mydirlock
  37. from the prototype above).  ExAll() fills a buffer (mybuffer from the above
  38. prototype) with partial or whole ExAllData structures (from <dos/exall.h>):
  39.  
  40. struct ExAllData {
  41.     struct ExAllData *ed_Next; /* Pointer to the next structure */
  42.     UBYTE *ed_Name;                    /* File name */
  43.     LONG  ed_Type;             /* File type */
  44.     ULONG ed_Size;             /* File size */
  45.     ULONG ed_Prot;             /* Protection bits (see FIBF_ definitions in <dos/dos.h> */
  46.     ULONG ed_Days;             /* Date in three longwords, forming a DateStamp. */
  47.     ULONG ed_Mins;
  48.     ULONG ed_Ticks;
  49.     UBYTE *ed_Comment;         /* File comment.  Cannot be used */
  50. };
  51.  
  52.  
  53.  
  54. ExAll() copies an ExAllData structure into mybuffer for each entry in the
  55. directory.  The size of the ExAllData structure depends on the value in
  56. mydatatype.  The mydatatype parameter can have the following values:
  57.  
  58. ED_NAME        - ed_Name - file name
  59. ED_TYPE        - ed_Type - file type (directory, file, soft link, etc.)
  60. ED_SIZE        - ed_Size - file size
  61. ED_PROTECTION    - ed_Prot - file protection bits
  62. ED_DATE        - ed_Days, ed_Mins, ed_Ticks - file date in long words
  63. ED_COMMENT        - ed_Comment - file comment (not currently supported).
  64.  
  65. Each of the possible mydatatype values corresponds to a field (or in the
  66. case of ED_DATE, a set of three fields) in the ExAllData structure.  When
  67. ExAll() writes an ExAllData structure to mybuffer, it writes only the field
  68. that corresponds to mydatatype plus the fields that precede that datatype
  69. in the ExAllData structure.  For example, if mydatatype is ED_SIZE, ExAll()
  70. would write ed_Next, ed_Type, and ed_Size to the buffer, ignoring the
  71. fields that follow ed_Size in the the ExAllData structure.
  72.  
  73. The ExAllData structures in mybuffer are organized into a linked list.  The
  74. ExAllData structure's ed_Next field either points to the next directory
  75. entry's ExAllData structure or is NULL if no directory entries follow.
  76. Applications should only access the ExAllData structures using this link
  77. list.
  78.  
  79. As ExAll() scans a directory, it copies partial or whole ExAllData
  80. structure into mybuffer until it either runs out of directory entries or
  81. until it runs out of room in mybuffer.  If ExAll() runs out of room, it
  82. will return a non-zero value, indicating that your application needs to
  83. perform more passes to finish scanning the directory.
  84.  
  85. To keep track of everything, ExAll() uses an application-supplied structure
  86. called ExAllControl (from <dos/exall.h>):
  87.  
  88. struct ExAllControl {
  89.     ULONG eac_Entries;        /* The number of entries returned in the buffer */
  90.     ULONG eac_LastKey;        /* Used to keep track of the position in the directory.  */
  91.                 /* Do not change this value! */
  92.     UBYTE *eac_MatchString;        /* Optional parsed pattern for pattern match.  */
  93.     struct Hook *eac_MatchFunc;
  94.                             /* Optional application hook to be called for each entry */
  95.                 /* Can be used to individually allow entries in the buffer or not */
  96. };
  97.  
  98.  
  99. The ExAllControl structure must be allocated and freed using
  100. AllocDosObject() and FreeDosObject():
  101.  
  102. myexallcontrol = AllocDosObject(DOS_EXALLCONTROL, NULL);
  103. FreeDosObject(DOS_EXALLCONTROL, myexallcontrol);
  104.  
  105.  
  106. The ExAllControl structure's eac_Entries field contains the number of
  107. directory entries that ExAll() wrote into mybuffer.  The eac_LastKey field
  108. is used by the file system to keep track of its place in the directory.  An
  109. application must set this field to zero before calling ExAll() and must not
  110. make any changes to this field between scans of a directory.
  111.  
  112. The eac_MatchString field is used to pattern match the names of directory
  113. entries using the standard AmigaDOS pattern matching functions (for more on
  114. AmigaDOS pattern matching see the article ``Using the AmigaDOS Pattern
  115. Matching Functions'' in the September/October issue of Amiga Mail.  If
  116. eac_MatchString is not NULL, ExAll() will only create ExAllData structures
  117. for the directory entries whose names match the matching string.  Note that
  118. this matching string must have been parsed by ParsePatternNoCase().  If
  119. eac_MatchString is NULL, ExAll() will not perform any pattern matching.
  120.  
  121. The eac_MatchFunc field points to an application-supplied hook function.
  122. If this hook is not NULL, ExAll() will call the hook function.  If the hook
  123. function returns TRUE, ExAll() will copy an ExAllData structure for this
  124. directory entry into mybuffer.  The hook is called in the following manner:
  125.  
  126. BOOL = MatchFunc(hookptr, exalldata, typeptr)
  127.                    A0        A1         A2
  128.  
  129. where:
  130.  
  131. hookptr is a pointer to the hook being called
  132. exalldata is a pointer to the exalldata structure of the current directory entry
  133. typeptr is a pointer to a longword indicating the type of the
  134.     ExAllData structure (mydatatype from the ExAll() prototype above).
  135.  
  136. By supplying a hook, each entry in the directory can be accepted or
  137. rejected according to your applications needs.  An application can use both
  138. the matching string and MatchFunc() to perform AmigaDOS pattern matching
  139. and custom matching on directory entries.
  140.  
  141. The code example ListDir.c at the end of this article is a simple example
  142. of how to use ExAll().  The example ListDir2.c is a more complicated
  143. example that uses pattern matching and a hook function.
  144.  
  145.  
  146. MultiDirectory Assigns
  147.  
  148. As of V36 it is possible to have a logical device assignment to more than
  149. one directory (see the dos.library Autodocs for AssignLock()/AssignAdd()).
  150. Since the user can utilize this with the C:Assign command, it is good
  151. practice to support this feature.  The shell itself supports multidirectory
  152. assigns, although not all C: commands do.  In general, when your
  153. application is presented with only a device name to scan, you should check
  154. if it is an assignment.  If it is, use GetDeviceProc() to get the handler
  155. for it, process it, and loop until GetDeviceProc() returns NULL, indicating
  156. there are no more directories for this assign.  See the Autodocs for
  157. details.
  158.  
  159. The program Find.c is a more realistic example of the usage of patterns and
  160. ExAll() and shows a method of supporting multidirectory assigns.  It scans
  161. one or more directories or volumes for the occurrence of a particular
  162. pattern.  This example recursively scans subdirectories which means that
  163. Find.c may need more stack space than normal to keep from overflowing the
  164. stack.  Find.c has two required arguments, a pattern and one or more
  165. directories to examine.  It has two keywords, FILES and DIRS, to tell it to
  166. scan only for files or directories, respectively.  The ALL keyword
  167. instructs Find.c to recurse into subdirectories when it encounters them.
  168.  
  169.  
  170. Filename Matching
  171.  
  172. The release 2.0 dos.library introduced several other functions for
  173. directory scanning:
  174.  
  175. LONG MatchFirst(UBYTE *mypattern, struct AnchorPath *myanchorpath);
  176. LONG MatchNext(struct AnchorPath *myanchorpath);
  177. VOID MatchEnd(struct AnchorPath *myanchorpath);
  178.  
  179. When using these functions, an application first calls MatchFirst(), which
  180. performs some initialization (like calling ParsePattern() on the pattern
  181. matching string, mypattern) and finds the first directory entry that
  182. matches the directory entry mypattern.  This pattern is relative to the
  183. current directory.   An application must use the the MatchNext() call to
  184. find subsequent matching directory entries.  After the application is done
  185. looking for matches or the application encounters an error, it must call
  186. MatchEnd() to release internal buffers.
  187.  
  188. Before using these functions, you need to set up an AnchorPath structure.
  189. This structure must be initialized by MatchFirst() and passed to
  190. MatchNext() and MatchEnd() so they can keep track of the directory scan.
  191. An application must not make any changes to this structure while in the
  192. middle of a directory scan (before calling MatchEnd()).  This AnchorPath
  193. structure must be longword aligned and is defined in <dos/dosasl.h> as
  194. follows:
  195.  
  196.  
  197. struct AnchorPath {
  198.     struct AChain   *ap_Base;   /* Pointer to the first anchor */
  199. #define ap_First ap_Base        /* Compatibility synonym. Don't use */
  200.     struct AChain   *ap_Last;   /* Pointer to the last anchor */
  201. #define ap_Current ap_Last      /* Compatiblity synomym. Don't use */
  202.     LONG    ap_BreakBits;       /* Bit flags to stop scanning */
  203.     LONG    ap_FoundBreak;      /* Bits flags which caused the stop */
  204.     BYTE    ap_Flags;           /* Behaviour flags */
  205.     BYTE    ap_Reserved;        /* Reserved for now */
  206.     WORD    ap_Strlen;          /* Buffer size for path name */
  207.                                 /* This used to be ap_Length  */
  208. #define ap_Length ap_Flags      /* Compatibility for LONGWORD ap_Length */
  209.                                 /* Don't use */
  210.     struct  FileInfoBlock ap_Info;  /* FileInfoBlock for matched entry */
  211.     UBYTE   ap_Buf[1];          /* Application allocated buffer for full */
  212.                                 /* path name*/
  213. };
  214.  
  215. If your application does not need a full path name to matching directory
  216. entries, it should initialize the ap_Strlen field to zero.  In this case,
  217. your application can get what it needs from the AnchorPath's ap_Info field.
  218. It can also get a lock on the directory from ap_Current->an_Lock field.  If
  219. your application needs the full path name of matching directory entries, it
  220. must allocate a buffer at the end of the AnchorPath structure and put the
  221. size of the buffer, in bytes, into ap_Strlen.
  222.  
  223. The ap_BreakBits field allows the user to abort a directory scan in
  224. progress.  The bits in this field correspond to the SIGBREAKF_ bits defined
  225. in <dos/dos.h>.  If the corresponding bit is set in ap_BreakBits,
  226. MatchFirst() or MatchNext() will stop a scan in progress if one of those
  227. signals occurs.  If this occurs, the bit of the signal that caused the
  228. break will be set in ap_FoundBreak.
  229.  
  230. With this information alone it is possible to perform simple file pattern
  231. matching.  As previously mentioned, the first match must be found with
  232. MatchFirst().  If MatchFirst() (or MatchNext()) cannot find a match or it
  233. encounters an error, it returns an error number, otherwise it returns a
  234. zero (which is unusual for a dos.library function).  If MatchFirst() does
  235. not encounter any problems, the application should look for subsequent
  236. matches by calling MatchNext().  The application should call MatchNext()
  237. until it returns an AmigaDOS error value.  MatchNext() accepts a pointer to
  238. the AnchorPath structure initialized by MatchFirst().
  239.  
  240. Normally, the error that MatchNext() returns is ERROR_NO_MORE_ENTRIES,
  241. indicating that there are no more directory entries that match mypattern.
  242. MatchEnd() is used to release any resources that were allocated in the
  243. scanning process.  Due to a number of bugs in the V36 implementation, these
  244. functions should only be used as of V37.  ListPattern.c is a simple example
  245. of using MatchFirst()/MatchNext().
  246.  
  247. For more complex matching, the ap_Flags field can be used to define the
  248. behavior of MatchFirst() and MatchNext().  Currently, there are several
  249. flags defined:
  250.  
  251. APF_ITSWILD
  252. APF_DODIR
  253. APF_DIDDIR
  254. APF_NOMEMERR
  255. APF_DirChanged
  256. APF_FollowHLinks
  257.  
  258.  
  259.  
  260. The APF_ITSWILD flag will be set if a wildcard was present in the pattern
  261. after the call to MatchFirst().  It will be used to instruct MatchNext()
  262. but your application can check it too and perform an action depending on
  263. its status.
  264.  
  265. The APF_DODIR flag instructs MatchFirst/Next() to enter a directory if it
  266. encounters one.  This flag can be set and reset on an individual basis.
  267. Once MatchNext() is finished processing a directory, it will set the
  268. APF_DIDDIR bit and will change the AnchorPath's directory back to the
  269. parent directory.
  270.  
  271. APF_NOMEMERR indicates that MatchFirst/Next() encountered a fatal out of
  272. memory error.  Processing the directory should be aborted and an error
  273. returned to the user.
  274.  
  275. The APF_DirChanged flag indicates that MatchNext() noticed that directory
  276. lock has changed since the previous MatchNext() call.
  277.  
  278. The APF_FollowHLinks flag tells MatchFirst/MatchNext() to follow hard link
  279. directories if the APF_DODIR bit is set.  This feature is in place to avoid
  280. confusing applications that do not know anything about hard links.
  281.  
  282. Most existing versions of the 2.0 include file <dos/dosasl.h> mention two
  283. other flags, APF_DOWILD and APF_DODOT.  These are not currently in use by
  284. the system.
  285.  
  286. The DirComp.c example is a more complex example of using
  287. MatchFirst()/Next().  It takes a path, which may include wildcards, and
  288. compares the directory entries it finds with those in the target directory.
  289. If the user specifies the DATE keyword, DirComp will also compare the
  290. datestamps.  The ALL keyword tells DirComp to do a recursive scan.  For
  291. deeply nested directories the BUFFER keyword can enlarge the buffer that
  292. DirComp uses from its standard 256 bytes up to 4096 bytes (calling it the
  293. ``Joanne'' keyword might be more appropriate).
  294.  
  295.  
  296.  
  297.